import os
import select
from socket import *
import struct
from multiprocessing import Manager, Pool

USER_DICT = {}


class Server:
    def __init__(self, ip, port):
        self.s_lisen: socket = None
        self.ip = ip
        self.port = port

    def tcp_init(self):
        # tcp端口启动
        self.s_lisen = socket(AF_INET, SOCK_STREAM)
        self.s_lisen.bind((self.ip, self.port))
        self.s_lisen.listen(128)

    def task(self, ):
        new_client, client_addr = self.s_lisen.accept()
        user = User(new_client)
        user.deal_commend()


class User:
    def __init__(self, new_client):
        self.new_client: socket = new_client
        self.user_nema = None
        self.path = os.getcwd()

    def deal_commend(self):
        # 处理客户的各种命令
        while True:
            command = self.train_recv().decode('utf-8')
            if command[:2] == 'ls':
                self.do_ls()
            elif command[:5] == 'rmdir':
                self.do_rmdir(command)
            elif command[:2] == 'cd':
                self.do_cd(command)
            elif command[:2] == 'rm':
                self.do_rm(command)
            elif command[:3] == 'pwd':
                self.do_pwd()
            elif command[:4] == 'gets':
                self.do_gets()
            elif command[:4] == 'puts':
                self.do_puts()

            else:
                print('wrong command')

    def train_send(self, bytess):
        # 发送数据
        if not isinstance(bytess, bytes):
            bytess = bytess.encode('utf-8')
        train_head = struct.pack('I', len(bytess))
        self.new_client.send(train_head + bytess)

    def train_recv(self):
        # 接收数据
        train_head_size = self.new_client.recv(4)
        train_head = struct.unpack('I', train_head_size)
        return self.new_client.recv(train_head[0])

    def do_ls(self):
        data = ''
        for file in os.listdir(self.path):
            data += file + ' ' * 5 + str(os.stat(file).st_size) + '\n'
        self.train_send(data.encode('utf8'))

    def do_rm(self, command):
        try:
            data = command.split()[1]
            os.remove(data)
            self.train_send('删除成功'.encode('utf8'))
        except:
            self.train_send("wrong command".encode('utf8'))

    def do_cd(self, command):
        try:
            data = command.split()[1]
            os.chdir(data)
            self.path = os.getcwd()
            self.train_send(self.path.encode('utf8'))
        except:
            self.train_send('无效目录'.encode('utf8'))

    def do_pwd(self):
        self.train_send(self.path.encode('utf8'))

    def do_gets(self):
        """recv不管接收多少个字符都会返回，所以当双方速度不匹配或recv缓冲区不够时会直接返回
        因此用while直接接收常量字节可出现接不够就上去接4个字节的大小去了，把内容当大小进行unpack解包时会
        是一个很大的数，从而导致接收出现问题"""
        flie_name = self.train_recv()
        self.send_flie(flie_name)

    def do_puts(self):
        pass

    def do_rmdir(self, command):
        try:
            data = command.split()[1]
            os.chdir(data)
            data_path = os.getcwd()
            for rm in os.listdir(data_path):
                os.remove(rm)
            os.rmdir(data)
            self.train_send('成功'.encode('utf8'))
        except:
            self.train_send('无效目录'.encode('utf8'))

    def send_flie(self, flie_name):
        """发送文件"""
        flie_size = os.stat(flie_name).st_size
        # 先发文件大小
        train_head = struct.pack('I', flie_size)
        self.new_client.send(train_head)
        f = open(flie_name, 'rb')
        while True:
            flie_content = f.read(1000)
            if flie_content:
                self.new_client.send(flie_content)
            else:
                break
        f.close()

    def recv_flie(self):
        """接收文件"""
        #先接文件名
        flie_name = self.train_recv()
        train_head = self.new_client.recv(4)
        train_head_unpack = struct.unpack('I', train_head)
        flie_size = train_head_unpack[0]
        total = 0
        f = open(flie_name, 'wb')
        while total < flie_size:
            data = self.new_client.recv(1000)
            f.write(data)
            total += len(data)



def run_poll(user):
    user.deal_commend()


if __name__ == '__main__':
    server = Server('', 2000)
    server.tcp_init()
    # d进程池只能传普通方法，不能传对象方法
    po = Pool()
    epoll = select.epoll()
    epoll.register(server.s_lisen.fileno(), select.EPOLLIN)
    while True:
        evens = epoll.poll()
        for fd, event in evens:
            if fd == server.s_lisen.fileno():
                new_client, client_addr = server.s_lisen.accept()
                user = User(new_client)
                USER_DICT[new_client] = user
                po.apply_async(run_poll, args=(user,))
